import os
import subprocess
import json
import re
import traceback
from urllib.parse import urlparse
from moviepy.editor import VideoFileClip
import whisper
from openai import OpenAI
from config import (
    VIDEOS_DIR,
    OPENAI_API_KEY
)

# 设置 OpenAI API Key
if OPENAI_API_KEY:
    client = OpenAI(
        # 若没有配置环境变量，请用百炼API Key将下行替换为：api_key="sk-xxx",
        api_key=OPENAI_API_KEY,
        base_url="https://dashscope.aliyuncs.com/compatible-mode/v1",
    )


def download_video(video_url: str) -> str:
    """
    使用 you-get 下载视频, 并实现缓存逻辑.
    :param video_url: Bilibili 视频的 URL.
    :return: 下载的视频文件的路径.
    """
    # 解析 URL 获取 path 部分
    parsed_url = urlparse(video_url)
    path = parsed_url.path

    # 处理 path 生成安全的文件名
    safe_path = re.sub(r'[^\w\-_.]', '_', path)  # 替换非法字符为下划线
    safe_path = re.sub(r'^_+|_+$', '', safe_path)  # 移除首尾下划线
    safe_path = re.sub(r'_+', '_', safe_path)  # 合并连续下划线
    expected_filename = f"{safe_path}.mp4"
    video_path = os.path.join(VIDEOS_DIR, expected_filename)

    # 检查缓存
    if os.path.exists(video_path):
        print(f"[+] 发现缓存视频: {video_path}")
        return video_path

    # 下载视频
    print(f"[+] 正在下载视频: {video_url}")
    try:
        # 使用 you-get 下载视频到指定目录
        result = subprocess.run(
            ['you-get', '--no-caption', '-o', VIDEOS_DIR, video_url],
            check=True,
            capture_output=True,
            text=True,
            encoding='utf-8'
        )
        print(result.stdout)

        # 查找下载的最新 MP4 文件
        files = [f for f in os.listdir(VIDEOS_DIR) if f.endswith('.mp4')]
        if not files:
            raise FileNotFoundError("视频下载后未找到任何 .mp4 文件.")
        latest_file_path = max([os.path.join(VIDEOS_DIR, f) for f in files], key=os.path.getctime)
        
        # 将下载的文件重命名为基于 URL path 的文件名
        os.rename(latest_file_path, video_path)

        print(f"[+] 视频下载完成并已重命名: {video_path}")
        return video_path
    except subprocess.CalledProcessError as e:
        print(f"[-] 视频下载失败: {e.stderr}")
        raise
    except Exception as e:
        print(f"[-] 处理视频下载时发生错误: {e}")
        raise

def extract_audio(video_path: str) -> str:
    """
    从视频文件中提取音频.
    :param video_path: 视频文件的路径.
    :return: 提取的音频文件的路径.
    """
    print(f"[+] 正在提取音频: {video_path}")
    try:
        # 获取视频文件所在目录
        video_dir = os.path.dirname(video_path)
        video_filename = os.path.basename(video_path)
        audio_filename = os.path.splitext(video_filename)[0] + '.mp3'
        audio_path = os.path.join(video_dir, audio_filename)

        # 确保视频目录存在
        os.makedirs(video_dir, exist_ok=True)

        if os.path.exists(audio_path):
            print(f"[+] 音频文件已存在: {audio_path}")
            return audio_path

        video_clip = VideoFileClip(video_path)
        audio_clip = video_clip.audio
        audio_clip.write_audiofile(audio_path, codec='mp3')
        
        video_clip.close()
        audio_clip.close()

        print(f"[+] 音频提取完成: {audio_path}")
        return audio_path
    except Exception as e:
        print(f"[-] 音频提取失败: {e}")
        raise

def transcribe_audio(audio_path: str) -> str:
    """
    使用 OpenAI Whisper 将音频转录为带时间戳的文本.
    :param audio_path: 音频文件的路径.
    :return: 保存转录结果的 JSON 文件路径.
    """
    print(f"[+] 正在转录音频: {audio_path}")
    try:
        # 检查转录文件是否已存在
        # 获取音频文件所在目录
        audio_dir = os.path.dirname(audio_path)
        transcript_filename = os.path.splitext(os.path.basename(audio_path))[0] + '.json'
        transcript_path = os.path.join(audio_dir, transcript_filename)

        # 确保目录存在
        os.makedirs(audio_dir, exist_ok=True)

        if os.path.exists(transcript_path):
            print(f"[+] 转录文件已存在: {transcript_path}")
            return transcript_path

        # 加载 Whisper 模型 (可以根据需要选择 'tiny', 'base', 'small', 'medium', 'large')
        # 'base' 模型在速度和准确性之间取得了很好的平衡
        model = whisper.load_model("base")
        
        # 进行转录, word_timestamps=True 可以获取每个单词的时间戳
        result = model.transcribe(audio_path, word_timestamps=True, verbose=True)

        # 将结果保存为 JSON 文件
        with open(transcript_path, 'w', encoding='utf-8') as f:
            json.dump(result, f, ensure_ascii=False, indent=4)

        print(f"[+] 音频转录完成: {transcript_path}")
        return transcript_path
    except Exception as e:
        print(f"[-] 音频转录失败: {e}")
        raise

def summarize_transcript(transcript_path: str) -> str:
    """
    使用 OpenAI GPT 模型总结转录文本, 并关联时间戳.
    :param transcript_path: 转录的 JSON 文件路径.
    :return: 保存总结内容的 Markdown 文件路径.
    """
    print(f"[+] 正在总结文本内容: {transcript_path}")
    if not OPENAI_API_KEY:
        raise ValueError("OpenAI API Key 未设置. 请在 .env 文件中配置.")

    try:
        with open(transcript_path, 'r', encoding='utf-8') as f:
            transcript_data = json.load(f)

        # 将带时间戳的文稿格式化为字符串
        full_text = ""
        for segment in transcript_data['segments']:
            start_time = int(segment['start'])
            # 将秒转换为 H:M:S 格式
            h, m, s = start_time // 3600, (start_time % 3600) // 60, start_time % 60
            time_str = f"[{h:02d}:{m:02d}:{s:02d}]"
            full_text += f"{time_str} {segment['text']}\n"

        # 获取转录文件所在目录
        transcript_dir = os.path.dirname(transcript_path)
        summary_filename = os.path.splitext(os.path.basename(transcript_path))[0] + '_summary.md'
        summary_path = os.path.join(transcript_dir, summary_filename)

        # 确保目录存在
        os.makedirs(transcript_dir, exist_ok=True)

        # 检查摘要文件是否已存在
        if os.path.exists(summary_path):
            print(f"[+] 摘要文件已存在: {summary_path}")
            return summary_path

        # 设计 Prompt
        prompt = f"""你是一个专业的视频内容分析师. 请根据以下带时间戳的视频文稿, 生成一份简洁、清晰、分点的摘要. 
                    规则:
                    1. 摘要需要捕捉视频的核心观点和主要信息.
                    2. 每个摘要点都应该尽可能独立和完整.
                    3. 在每个摘要点的末尾, 使用 `(视频节点: HH:MM:SS)` 的格式, 标注出该观点在原文稿中最相关的起始时间戳.
                    4. 输出格式为 Markdown.

                    这是视频文稿:
                    ---
                    {full_text}
                    ---

                    请生成摘要:
                    """

        print("[+] 正在调用 OpenAI API 进行总结...")
        completion = client.chat.completions.create(
            # 模型列表：https://help.aliyun.com/zh/model-studio/getting-started/models
            model="qwen-plus",
            messages=[
                {"role": "system", "content": "你是一个专业的视频内容分析师."},
                {"role": "user", "content": prompt}
            ],
            # Qwen3模型通过enable_thinking参数控制思考过程（开源版默认True，商业版默认False）
            # 使用Qwen3开源版模型时，若未启用流式输出，请将下行取消注释，否则会报错
            extra_body={"enable_thinking": False},
        )
        # response = openai.ChatCompletion.create(
        #     model="gpt-3.5-turbo",
        #     messages=[
        #         {"role": "system", "content": "你是一个专业的视频内容分析师."},
        #         {"role": "user", "content": prompt}
        #     ],
        #     temperature=0.5,
        # )

        # 验证API响应
        if not completion.choices or len(completion.choices) == 0:
            raise ValueError("API返回结果中没有找到有效的choices")
        
        summary_content = completion.choices[0].message.content
        if not summary_content:
            raise ValueError("API返回的摘要内容为空")
        
        print(f"[+] API返回摘要内容: {summary_content[:100]}...")  # 打印前100字符

        # 保存总结
        with open(summary_path, 'w', encoding='utf-8') as f:
            f.write(summary_content)

        print(f"[+] 内容总结完成: {summary_path}")
        return summary_path

    except Exception as e:
        print(f"[-] 内容总结失败: {str(e)}")
        print("[-] 详细错误信息:")
        traceback.print_exc()
        raise